package com.gitee.wsl.collections.list

import com.gitee.wsl.collections.delegate.DelegatingList
import com.gitee.wsl.func.factory.Factory
import com.gitee.wsl.func.transform.Transformer

/**
 * Decorates another `List` to create objects in the list on demand.
 *
 *
 * When the [.get] method is called with an index greater than
 * the size of the list, the list will automatically grow in size and return
 * a new object from the specified factory or transformer. The gaps will be
 * filled by null. If a get method call encounters a null, it will be replaced
 * with a new object from the factory. Thus this list is unsuitable for
 * storing null objects.
 *
 *
 *
 * For instance:
 *
 *
 * <pre>
 * Factory&lt;Date&gt; factory = new Factory&lt;Date&gt;() {
 * public Date create() {
 * return new Date();
 * }
 * }
 * List&lt;Date&gt; lazy = LazyList.decorate(new ArrayList&lt;Date&gt;(), factory);
 * Date date = lazy.get(3);
</pre> *
 *
 *
 *
 * After the above code is executed, `date` will contain
 * a new `Date` instance.  Furthermore, that `Date`
 * instance is the fourth element in the list.  The first, second,
 * and third element are all set to `null`.
 *
 *
 *
 * This class differs from [GrowthList] because here growth occurs on
 * get, where `GrowthList` grows on set and add. However, they
 * could easily be used together by decorating twice.
 *
 *
 *
 * This class is Serializable from Commons Collections 3.1.
 *
 *
 * @param <E> the type of the elements in the list.
 * @see GrowthList
 *
 * @since 3.0
</E> */
class LazyList<E> : DelegatingList<E?> {
    /** The factory to use to lazily instantiate the objects  */
    private val factory: Factory<E>?

    /** The transformer to use to lazily instantiate the objects  */
    private val transformer: Transformer<Int, out E>?

     var delegate2: MutableList<E?>

    /**
     * Constructor that wraps (not copies).
     *
     * @param list  the list to decorate, must not be null
     * @param factory  the factory to use for creation, must not be null
     * @throws NullPointerException if list or factory is null
     */
    protected constructor(list: MutableList<E?>, factory: Factory< E>) : super(list) {
        this.factory = factory
        this.transformer = null
        delegate2 = list
    }

    /**
     * Constructor that wraps (not copies).
     *
     * @param list  the list to decorate, must not be null
     * @param transformer  the transformer to use for creation, must not be null
     * @throws NullPointerException if list or transformer is null
     */
    protected constructor(list: MutableList<E?>, transformer: Transformer<Int, out E>) : super(list) {
        this.factory = null
        this.transformer = transformer
        delegate2 = list
    }

    private fun element(index: Int): E? {
        if (factory != null) {
            return factory.create()
        }
        if (transformer != null) {
            return transformer.apply(index)
        }
        throw IllegalStateException("Factory and Transformer are both null!")
    }

    fun decorated() = delegate2

    /**
     * Decorate the get method to perform the lazy behavior.
     *
     *
     * If the requested index is greater than the current size, the list will
     * grow to the new size and a new object will be returned from the factory
     * or transformer. Indexes in-between the old size and the requested size
     * are left with a placeholder that is replaced with a factory or
     * transformer object when requested.
     *
     * @param index  the index to retrieve
     * @return the element at the given index
     */
    override fun get(index: Int): E? {
        val size: Int = decorated().size
        if (index < size) {
            // within bounds, get the object
            var `object` = decorated()[index]
            if (`object` == null) {
                // item is a placeholder, create new one, set and return
                `object` = element(index)
                decorated().set(index, `object`)
            }
            // good and ready to go
            return `object`
        }
        // we have to grow the list
        for (i in size..<index) {
            decorated().add(null)
        }
        // create our last object, set and return
        val `object` = element(index)
        decorated().add(`object`)
        return `object`
    }

    override fun subList(fromIndex: Int, toIndex: Int): List<E?> {
        val sub = decorated().subList(fromIndex, toIndex)
        if (factory != null) {
            return LazyList(sub, factory)
        }
        if (transformer != null) {
            return LazyList(sub, transformer)
        }
        throw IllegalStateException("Factory and Transformer are both null!")
    }

    companion object {

        /**
         * Factory method to create a lazily instantiating list.
         *
         * @param <E> the type of the elements in the list
         * @param list  the list to decorate, must not be null
         * @param factory  the factory to use for creation, must not be null
         * @return a new lazy list
         * @throws NullPointerException if list or factory is null
         * @since 4.0
        </E> */
        fun <E> lazyList(list: MutableList<E?>, factory: Factory<E>): LazyList<E> {
            return LazyList(list, factory)
        }

        /**
         * Transformer method to create a lazily instantiating list.
         *
         * @param <E> the type of the elements in the list
         * @param list  the list to decorate, must not be null
         * @param transformer  the transformer to use for creation, must not be null
         * @return a new lazy list
         * @throws NullPointerException if list or transformer is null
         * @since 4.4
        </E> */
        fun <E> lazyList(list: MutableList<E?>, transformer: Transformer<Int,  E>): LazyList<E> {
            return LazyList(list, transformer)
        }
    }
}
